using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Security.Cryptography;

namespace stsdev {

    #region "Custom Types used by SolutionBuilder"
    public enum SolutionVersionTypeEnum {
        VS2005,
        VS2008_30,
        VS2008_35
    }

    public enum AssemblyDeploymentTarget {
        WebApplication,
        GlobalAssemblyCache
    }
    public struct SolutionSafeControlEntry {
        public string Assembly;
        public string Namespace;
        public string TypeName;
        public string Safe;
    }

    public struct SolutionAssembly {
        public string Location;
        public string DeploymentTarget;
        public List<SolutionSafeControlEntry> SafeControlEntries;
    }
    #endregion

    public class SolutionBuilder {

        #region "Solution/Project Properties"

        private static ISolutionProvider _SolutionProvider;
        public static ISolutionProvider SolutionProvider {
            get { return _SolutionProvider; }
            set { _SolutionProvider = value; }
        }

        private static string _SolutionName;
        public static string SolutionName {
            get { return _SolutionName; }
            set { _SolutionName = value; }
        }

        // 4/14/2009 - bphillips - _PrimaryFeatureName must be set to a default value or builds of older projects will fail.
        private static string _PrimaryFeatureName = "feature.xml";
        public static string PrimaryFeatureName {
            get { return _PrimaryFeatureName; }
            set { _PrimaryFeatureName = value; }
        }

        private static List<string> _SecondaryFeatures = new List<string>();
        public static List<string> SecondaryFeatures {
            get { return _SecondaryFeatures; }
        }

        private static string _SolutionDirectory;
        public static string SolutionDirectory {
            get { return _SolutionDirectory; }
            set { _SolutionDirectory = value; }
        }

        private static string _SolutionId;
        public static string SolutionId {
            get { return _SolutionId; }
            set { _SolutionId = value; }
        }

        private static SolutionVersionTypeEnum _SolutionVersionType = SolutionVersionTypeEnum.VS2005;
        public static SolutionVersionTypeEnum SolutionVersionType {
            get { return _SolutionVersionType; }
            set { _SolutionVersionType = value; }
        }

        private static string _ProjectGuid;
        public static string ProjectGuid {
            get { return _ProjectGuid; }
            set { _ProjectGuid = value; }
        }

        // added to support WF Template projects by TPattison on 4/29 
        private static string _ProjectTypeGuids = string.Empty;
        public static string ProjectTypeGuids {
            get { return _ProjectTypeGuids; }
            set { _ProjectTypeGuids = value; }
        }
        // end of 4/29 addition by TPattison

        private static bool _ResetWebServer;
        public static bool ResetWebServer {
            get { return _ResetWebServer; }
            set { _ResetWebServer = value; }
        }

        private static bool _AssemblyDeployment = true;
        public static bool AssemblyDeployment {
            get { return _AssemblyDeployment; }
            set {
                _AssemblyDeployment = value;
                if (value == false) {
                    _SafeControlSettings = false;
                    _CasPermissions = false;
                }
            }
        }

        private static string _KeyFileSource;
        public static string KeyFileSource {
            get { return _KeyFileSource; }
            set {
                _KeyFileSource = value;
                _KeyFileName = value.Substring(value.LastIndexOf(@"\") + 1);
            }
        }

        private static string _KeyFileName;
        public static string KeyFileName {
            get { return _KeyFileName; }
            set { _KeyFileName = value; }
        }

        private static bool _SafeControlSettings = false;
        public static bool SafeControlSettings {
            get { return _SafeControlSettings; }
            set { _SafeControlSettings = value; }
        }

        private static AssemblyDeploymentTarget _DeploymentTarget = AssemblyDeploymentTarget.GlobalAssemblyCache;
        public static AssemblyDeploymentTarget DeploymentTarget {
            get { return _DeploymentTarget; }
            set { _DeploymentTarget = value; }
        }

        private static bool _CasPermissions = false;
        public static bool CasPermissions {
            get { return _CasPermissions; }
            set { _CasPermissions = value; }
        }

        private static XmlNode _CasPermissionsNode;
        public static XmlNode CasPermissionsNode {
            get { return _CasPermissionsNode; }
            set { _CasPermissionsNode = value; }
        }

        private static string _TargetName;
        public static string TargetName {
            get { return _TargetName; }
            set { _TargetName = value; }
        }

        private static string _TargetPath;
        public static string TargetPath {
            get { return _TargetPath; }
            set {
                _TargetPath = value;
                //01-NOV-08 jthake: added to allow resetting TargetPath
                if (_TargetPath != null) {
                    // 20090702 - bphillips - Modified to only update FullAssemblyName using reflection if the file exists.  Otherwise, do it manually.
                    if (File.Exists(_TargetPath)) {
                        Assembly asm = Assembly.LoadFile(_TargetPath);
                        FullAssemblyName = asm.FullName;
                    } else {
                        FullAssemblyName = SolutionName + ", Version=1.0.0.0, Culture=neutral, PublicKeyToken=" + GetPublicKeyToken();
                    }
                    // End of 20090702 - bphillips
                }
            }
        }

        private static string _FullAssemblyName;
        public static string FullAssemblyName {
            get { return _FullAssemblyName; }
            set { _FullAssemblyName = value; }
        }

        private static List<SolutionAssembly> _Assemblies = new List<SolutionAssembly>();
        public static List<SolutionAssembly> Assemblies {
            get { return _Assemblies; }
            set { _Assemblies = value; }
        }

        private static string _StsAdmDeployParameters = "-immediate";
        public static string StsAdmDeployParameters {
            get { return _StsAdmDeployParameters; }
            set { _StsAdmDeployParameters = value; }
        }

        private static string _StsAdmUpgradeParameters = "-local";
        public static string StsAdmUpgradeParameters {
            get { return _StsAdmUpgradeParameters; }
            set { _StsAdmUpgradeParameters = value; }
        }

        private static string _StsAdmRetractParameters = "-immediate";
        public static string StsAdmRetractParameters {
            get { return _StsAdmRetractParameters; }
            set { _StsAdmRetractParameters = value; }
        }

        // Added 4/2/2009 - bphillips - Needed to put the release version of dll when in ReleaseBuild mode.
        private static string _configurationName;
        public static string ConfigurationName {
            get { return _configurationName; }
            set { _configurationName = value; }
        }

        // Added 4/2/2009 - bphillips - Allow custom feature image
        private static string _imageFileSource;
        public static string ImageFileSource {
            get { return _imageFileSource; }
            set { _imageFileSource = value; }
        }

        public static string ImageFileName {
            get {
                if (!string.IsNullOrEmpty(_imageFileSource) && _imageFileSource.IndexOf("\\") > -1) {
                    return _imageFileSource.Substring(_imageFileSource.LastIndexOf("\\") + 1);
                }

                return "AfricanPith32.gif";
            }
        }

        // Added 4/3/2009 - bphillips - Allow user to select app pool
        private static string _targetAppPool;
        public static string TargetAppPool {
            get { return _targetAppPool; }
            set { _targetAppPool = value; }
        }

        // Added 4/3/2009 - bphillips - Add support for IIS7 or later.
        private static IISVersionEnum _iisVersion;
        public static IISVersionEnum IISVersion {
            get { return _iisVersion; }
            set { _iisVersion = value; }
        }

        // Added 4/3/2009 - bphillips - Enable ASP.Net Designer support
        private static bool _enableASPNetSupport;
        public static bool EnableASPNetSupport {
            get { return _enableASPNetSupport; }
            set { _enableASPNetSupport = value; }
        }

        // Added 4/3/2009 - bphillips - Enable WF Designer support
        private static bool _enableWFSupport;
        public static bool EnableWFSupport {
            get { return _enableWFSupport; }
            set { _enableWFSupport = value; }
        }

        #endregion

        #region "Visual Studio Configurations"

        public static string[] Configurations = 
      { "DebugBuild",
        "DebugInstall",
        "DebugDeploy",
        "DebugRedeploy",
        "DebugUpgrade",
        "DebugRefreshAssemblyInGac", // added by TPattison on 4/29
        "DebugQuickCopy",
        "DebugQuickCopyAndGAC", // Added 20090719 - bphillips
        "DebugRetract",
        "DebugDelete",
        "ReleaseBuild"};
        #endregion

        #region "Project Assembly References List"
        private static string[] DefaultProjectAssemblyReferences = 
      { 
        "System",
        "System.Web",
        "System.Xml",
        "Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL"
      };

        public static List<string> ProjectAssemblyReferences = new List<string>(DefaultProjectAssemblyReferences);

        #endregion

        #region "Solution Provider List"

        private static ISolutionProvider[] _SolutionProviders =
      { new EmptySolutionProvider(),        
        new EmptySolutionWithAssemblyProvider(),
        new ImageOnlySolutionProvider(),
        new SimpleFeatureSolutionProvider(),
        new FeatureWithApplicationPageSolutionProvider(),
        new WebPartSolutionProvider(),
        new WebPartWithCasPermissionsSolutionProvider(),
        new SequentialWorkflowSolutionProvider(),
        new StateMachineWorkflowSolutionProvider() };

        public static List<ISolutionProvider>
          SolutionProviders = new List<ISolutionProvider>(_SolutionProviders);

        private static void InitializeExternalSolutionProviders() {
            string StsDevExePath = Assembly.GetExecutingAssembly().Location;
            string StsDevDirectory = StsDevExePath.Substring(0, StsDevExePath.LastIndexOf(@"\"));
            string SolutionProvidersXmlPath = StsDevDirectory + @"\SolutionProviders.xml";

            if (File.Exists(SolutionProvidersXmlPath)) {
                XmlDocument doc = new XmlDocument();
                doc.Load(SolutionProvidersXmlPath);
                XmlElement RootElement = doc.DocumentElement;
                foreach (XmlNode ChildNode in RootElement.ChildNodes) {
                    if (ChildNode.Name.Equals("Clear")) {
                        SolutionProviders.Clear();
                    }
                    if (ChildNode.Name.Equals("Add")) {
                        string ClassName = ChildNode.Attributes["Class"].Value;
                        string AssemblyName = ChildNode.Attributes["Assembly"].Value;
                        SolutionProviders.Add(LoadSolutionProvider(ClassName, AssemblyName));
                    }
                }
            }
        }

        private static ISolutionProvider LoadSolutionProvider(string ClassName, string AssemblyName) {
            Assembly asm = Assembly.Load(AssemblyName);
            Type ProviderClass = asm.GetType(ClassName);
            Type[] ConstructorArgTypes = { };
            ConstructorInfo ProviderConstructor = ProviderClass.GetConstructor(ConstructorArgTypes);
            object[] ConstructorArgs = { };
            return (ISolutionProvider) ProviderConstructor.Invoke(ConstructorArgs);
        }

        #endregion

        public static void RunCreateSolutionWizard() {

            InitializeExternalSolutionProviders();

            SelectSolutionType dlg = new SelectSolutionType();
            dlg.InitializeSolutionProviders(SolutionProviders);
            DialogResult result = dlg.ShowDialog();
            if (result == DialogResult.OK) {
                // create standard project structure
                SolutionName = dlg.GetSolutionName();
                SolutionDirectory = dlg.GetParentDirectory() + @"\" + SolutionName;
                SolutionVersionType = dlg.GetSolutionVersionType();
                SolutionProvider = dlg.GetSelectedProvider();
                KeyFileSource = dlg.GetSigningKeyFile();
                ImageFileSource = dlg.GetImageFile();
                TargetAppPool = dlg.GetAppPool();
                IISVersion = dlg.GetIISVersion();
                EnableASPNetSupport = dlg.GetEnableASPNetSupport();
                EnableWFSupport = dlg.GetEnableWFSupport();

                // Added 4/3/2009 - bphillips - Add support for workflow and ASP.Net designers
                if (SolutionBuilder.EnableWFSupport) {
                    if (ProjectTypeGuids.ToLower().IndexOf(ProjectFileBuilder.WorkflowProjectTypeGuid.ToLower()) == -1) {
                        ProjectTypeGuids += ";" + ProjectFileBuilder.WorkflowProjectTypeGuid;
                    }
                }

                if (SolutionBuilder.EnableASPNetSupport) {
                    if (ProjectTypeGuids.ToLower().IndexOf(ProjectFileBuilder.WebApplicationProjectTypeGuid.ToLower()) == -1) {
                        ProjectTypeGuids += ";" + ProjectFileBuilder.WebApplicationProjectTypeGuid;
                    }
                }

                if (SolutionBuilder.EnableASPNetSupport || SolutionBuilder.EnableWFSupport) {
                    if (ProjectTypeGuids.ToLower().IndexOf(ProjectFileBuilder.ExtraSupportProjectTypeGuid.ToLower()) == -1) {
                        ProjectTypeGuids += ";" + ProjectFileBuilder.ExtraSupportProjectTypeGuid;
                    }
                }

                ProjectTypeGuids = ProjectTypeGuids.Trim(';');
                // end of Added 4/3/2009 - bphillips

                // create standard solution/project structure
                InitializeSolution();
                // call upon SolutionProvider to create solution
                SolutionProvider.AddSolutionItems();
                // fanalize building solution
                CompleteSolution();
                string SuccessMessage = "New solution " +
                                        SolutionName +
                                        " successfully created at " +
                                        SolutionDirectory;
                MessageBox.Show(SuccessMessage, "STSDEV");

                // Jeremy Sublett - 8-10-09 removed implementation of LaunchSolutionOnComplete since VS8 may not be installed or may not be the desired version
                //if (SolutionProvider.LaunchSolutionOnComplete) {
                //    ProcessStartInfo pInfo = new ProcessStartInfo();
                //    pInfo.UseShellExecute = false;
                //    pInfo.WorkingDirectory = SolutionDirectory + @"\";
                //    pInfo.FileName = @"C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe";
                //    // Modified 3/25/08 RHoward - added quotes to the beginning and end of the argument so that paths with spaces work properly
                //    pInfo.Arguments = '"' + SolutionDirectory + @"\" + SolutionName + @".sln""";
                //    // End 3/25/08 Modification
                //    pInfo.CreateNoWindow = false;
                //    Process.Start(pInfo);
                //}

            } else {
                MessageBox.Show("STSDEV Wizard Cancelled by User", "Goodbye from STSDEV");
            }

        }

        public static void InitializeSolution() {
            // 
            SolutionBuilder.SolutionProvider.InitializeSolution();
            // create GUID for project
            ProjectGuid = Guid.NewGuid().ToString().ToUpper();
            // create solution directory
            Directory.CreateDirectory(SolutionDirectory);
            Directory.SetCurrentDirectory(SolutionDirectory);
            // create DeploymentFiles directory
            Directory.CreateDirectory(Globals.DeploymentFilesFolder);
            ProjectFileBuilder.AddFolder(Globals.DeploymentFilesFolder);
            // create RootFiles directory
            Directory.CreateDirectory(Globals.RootFilesFolder);
            ProjectFileBuilder.AddFolder(Globals.RootFilesFolder);

            if (AssemblyDeployment) {
                // create AssemblyInfo.cs      
                AssemblyInfoBuilder.Create();

                // add Strong Name Key file
                //David McWee 6/9/2008 - Preserve the name of the KeyFileName, this gives a "warm fuzzy" to the user that the correct key is being used
                //KeyFileName = "KeyFile.snk";
                StrongNameKeyBuilder.AddKeyFileToProject();


                // create .csproj file for initial build of assembly1        
                ProjectFileBuilder.Create(SolutionBuilder.SolutionName, ProjectGuid);

                // set target name and path after assembly compilation
                SolutionBuilder.TargetName = SolutionBuilder.SolutionName;
                SolutionBuilder.TargetPath = SolutionBuilder.SolutionDirectory +
                                             Globals.DebugTargetPath + @"\" +
                                             SolutionBuilder.SolutionName + ".dll";
            }

            SolutionBuilder.StsAdmDeployParameters = "-immediate";
            SolutionBuilder.StsAdmUpgradeParameters = "-local";
            SolutionBuilder.StsAdmRetractParameters = "-immediate";

            if (AssemblyDeployment) {
                SolutionBuilder.StsAdmDeployParameters += " -allowgacdeployment";
                SolutionBuilder.StsAdmUpgradeParameters += " -allowgacdeployment";
            }
            if (CasPermissions) {
                SolutionBuilder.StsAdmDeployParameters += " -allowcaspolicies";
                SolutionBuilder.StsAdmUpgradeParameters += " -allowcaspolicies";
            }
            if (SafeControlSettings || DeploymentTarget == AssemblyDeploymentTarget.WebApplication) {
                SolutionBuilder.StsAdmDeployParameters += " -allcontenturls";
                SolutionBuilder.StsAdmRetractParameters += " -allcontenturls";
            }

            PermissionSet CasPermissionSet = null;
            if (CasPermissions && (SolutionProvider is IPartiallyTrustedSolutionProvider)) {
                CasPermissionSet = ((IPartiallyTrustedSolutionProvider) SolutionProvider).CreatePermissionSet();
            }

            CreateDeploymentFiles(AssemblyDeployment, SafeControlSettings, DeploymentTarget, CasPermissionSet);

        }

        public static void CreateDeploymentFiles(bool AssemblyDeployment, bool SafeControlSettings, AssemblyDeploymentTarget DeploymentTarget, PermissionSet CasPermissionSet) {

            // create SolutionConfig.xml
            SolutionConfigBuilder.Create(Globals.SolutionConfigPath, AssemblyDeployment, SafeControlSettings, DeploymentTarget, CasPermissionSet);
            ProjectFileBuilder.AddSourceFile(Globals.SolutionConfigPath, SourceFileTypeEnum.None);

            // load settings from SolutionConfig.xml
            LoadSolutionConfigFile();

            // create Microsoft.SharePoint.targets      
            TargetsBuilder.Create(Globals.TargetsFilePath);
            ProjectFileBuilder.AddSourceFile(Globals.TargetsFilePath, SourceFileTypeEnum.None);

            // create manifest.xml
            ManifestBuilder.Create(Globals.ManifestXmlPath, AssemblyDeployment);
            ProjectFileBuilder.AddSourceFile(Globals.ManifestXmlPath, SourceFileTypeEnum.None);

            // create SolutionPackage.ddf
            CabDdfBuilder.Create(Globals.SolutionPackageDdfPath);
            ProjectFileBuilder.AddSourceFile(Globals.SolutionPackageDdfPath, SourceFileTypeEnum.None);

        }

        public static void RefreshDeploymentFiles(string TargetSolutionName, string TargetSolutionDirectory) {
            // echo to output window      
            Console.WriteLine("Current Solution Name: " + SolutionName);
            Console.WriteLine("Current Solution Directory: " + SolutionDirectory);
            Console.WriteLine("Refreshing deployment files...");

            // initialize static properties of SolutionBuilder class
            SolutionName = TargetSolutionName;
            TargetName = TargetSolutionName;
            SolutionDirectory = TargetSolutionDirectory;
            // call overloaded implementation
            RefreshDeploymentFiles();
        }

        public static void RefreshDeploymentFiles() {

            // set current directory
            Directory.SetCurrentDirectory(SolutionDirectory);

            // load in settings from SolutionConfig.xml
            LoadSolutionConfigFile();

            if (AssemblyDeployment) {
                // 20090702 - bphillips - Modified to build TargetPath based on build.
                if (!string.IsNullOrEmpty(SolutionBuilder.ConfigurationName) && SolutionBuilder.ConfigurationName.ToLower().StartsWith("release")) {
                    // set target path
                    TargetPath = SolutionDirectory + @"\" +
                                 Globals.ReleaseTargetPath + @"\" +
                                 SolutionName + ".dll";
                } else {
                    // set target path
                    TargetPath = SolutionDirectory + @"\" +
                                 Globals.DebugTargetPath + @"\" +
                                 SolutionName + ".dll";
                }
                // End of 20090702 - bphillips
            }

            // Added 20090403 - bphillips - Automatically make the manifest and DDF files writeable.
            if (File.Exists(Globals.ManifestXmlPath) && (File.GetAttributes(Globals.ManifestXmlPath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) {
                Console.WriteLine("Resetting read-only attribute on " + Globals.ManifestXmlPath);
                File.SetAttributes(Globals.ManifestXmlPath, File.GetAttributes(Globals.ManifestXmlPath) & ~FileAttributes.ReadOnly);
            }

            if (File.Exists(Globals.SolutionPackageDdfPath) && (File.GetAttributes(Globals.SolutionPackageDdfPath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) {
                Console.WriteLine("Resetting read-only attribute on " + Globals.SolutionPackageDdfPath);
                File.SetAttributes(Globals.SolutionPackageDdfPath, File.GetAttributes(Globals.SolutionPackageDdfPath) & ~FileAttributes.ReadOnly);
            }
            // End of Added 20090403 - bphillips

            // create Manifest.xml
            Console.WriteLine("Rebuilding " + Globals.ManifestXmlPath);
            ManifestBuilder.Create(Globals.ManifestXmlPath, AssemblyDeployment, ResetWebServer);

            // create SolutionPackage.ddf
            Console.WriteLine("Rebuilding " + Globals.SolutionPackageDdfPath);
            CabDdfBuilder.Create(Globals.SolutionPackageDdfPath);

        }

        public static void LoadSolutionConfigFile() {
            // clear Assemblies collection
            _Assemblies.Clear();

            if (!File.Exists(Globals.SolutionConfigPath)) {
                SolutionConfigBuilder.Create(Globals.SolutionConfigPath, true);
            }

            XmlDocument SolutionConfig = new XmlDocument();
            SolutionConfig.Load(Globals.SolutionConfigPath);

            XmlNode SolutionIdNode = SolutionConfig.SelectSingleNode(@"/Solution/SolutionId");
            _SolutionId = SolutionIdNode.InnerText;

            XmlNode SolutionNameNode = SolutionConfig.SelectSingleNode(@"/Solution/SolutionName");
            _SolutionName = SolutionNameNode.InnerText;

            XmlNode FeatureNameNode = SolutionConfig.SelectSingleNode(@"/Solution/Features");
            if (FeatureNameNode != null) {
                XmlNodeList featureNodes = FeatureNameNode.ChildNodes;
                foreach (XmlNode featureNode in featureNodes) {
                    XmlAttribute attr = featureNode.Attributes["Primary"];
                    if (attr != null && attr.Value.Equals("True")) {
                        _PrimaryFeatureName = featureNode.InnerText;
                    } else
                        _SecondaryFeatures.Add(featureNode.InnerText);
                }
            }

            XmlNode ResetWebServerNode = SolutionConfig.SelectSingleNode(@"/Solution/ResetWebServer");
            _ResetWebServer = Convert.ToBoolean(ResetWebServerNode.InnerText);

            XmlNode AssemblyDeploymentNode = SolutionConfig.SelectSingleNode(@"/Solution/AssemblyDeployment");
            _AssemblyDeployment = Convert.ToBoolean(AssemblyDeploymentNode.InnerText);


            XmlNode SafeControlSettingsNode = SolutionConfig.SelectSingleNode(@"/Solution/SafeControlSettings");
            _SafeControlSettings = Convert.ToBoolean(SafeControlSettingsNode.InnerText);

            XmlNode CasPermissionsEnabledNode = SolutionConfig.SelectSingleNode(@"/Solution/CasPermissions");
            _CasPermissions = Convert.ToBoolean(CasPermissionsEnabledNode.InnerText);

            if (_AssemblyDeployment) {
                XmlNode SolutionAssembliesNode = SolutionConfig.SelectSingleNode(@"/Solution/Assemblies");
                foreach (XmlNode SolutionAssemblyNode in SolutionAssembliesNode.ChildNodes) {
                    SolutionAssembly asm;
                    asm.Location = SolutionAssemblyNode.Attributes["Location"].Value;
                    asm.DeploymentTarget = SolutionAssemblyNode.Attributes["DeploymentTarget"].Value;
                    asm.SafeControlEntries = new List<SolutionSafeControlEntry>();
                    foreach (XmlNode SafeControlEntriesNode in SolutionAssemblyNode.ChildNodes) {
                        foreach (XmlNode SafeControlEntryNode in SafeControlEntriesNode.ChildNodes) {
                            SolutionSafeControlEntry sce;
                            sce.Assembly = SafeControlEntryNode.Attributes["Assembly"].Value;
                            sce.Namespace = SafeControlEntryNode.Attributes["Namespace"].Value;
                            sce.TypeName = SafeControlEntryNode.Attributes["TypeName"].Value;
                            sce.Safe = SafeControlEntryNode.Attributes["Safe"].Value;
                            asm.SafeControlEntries.Add(sce);
                        }
                    }
                    _Assemblies.Add(asm);
                }
            }

            if (_CasPermissions) {
                CasPermissionsNode = SolutionConfig.SelectSingleNode(@"/Solution/CodeAccessSecurity/PolicyItem/PermissionSet");
            }

        }

        public static void CompleteSolution() {
            // create project file
            ProjectFileBuilder.Create(SolutionBuilder.SolutionName, ProjectGuid);
            // create solution file
            SolutionFileBuilder.Create(SolutionBuilder.SolutionName, ProjectGuid);
            // refresh depoyment files
            SolutionBuilder.RefreshDeploymentFiles();
        }


        public static string GetPublicKeyToken() {
            // Modified 20090926 - bphillips - Return blank key token if no snk file specified.
            if (string.IsNullOrEmpty(KeyFileSource)) {
                return string.Empty;
            }

            StrongNameKeyPair keyPair = new StrongNameKeyPair(File.ReadAllBytes(KeyFileSource));
            SHA1Managed sha1 = new SHA1Managed();
            byte[] hash = sha1.ComputeHash(keyPair.PublicKey);

            byte[] publicKeyToken = new byte[8];

            Array.Copy(hash, hash.Length - publicKeyToken.Length, publicKeyToken, 0, publicKeyToken.Length);
            Array.Reverse(publicKeyToken);

            StringBuilder sb = new StringBuilder();
            foreach (byte b in publicKeyToken) {
                string hex = b.ToString("X").ToLower().PadLeft(2, '0');
                sb.Append(hex);
            }

            return sb.ToString();
        }
    }
}
